package com.liyunc.demo.base.table.coustomtable;

import javax.swing.DefaultCellEditor;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.event.CellEditorListener;
import javax.swing.event.ChangeEvent;
import javax.swing.event.MouseInputListener;
import javax.swing.plaf.basic.BasicTableHeaderUI;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
import java.awt.Component;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.util.EventObject;
import java.util.Vector;

public class ScriptManagerTable extends JTable {
    private static final long serialVersionUID = 1L;


    private static final int TABLE_ROW_HEIGHT = 65;

    private static final String TABLE_COLUMN_ID = "序号";
    private static final String TABLE_COLUMN_NAME = "名称";
    private static final String TABLE_COLUMN_CASE = "用例";
    private static final String TABLE_COLUMN_KEY = "关键词";
    private static final String TABLE_COLUMN_RESULT = "结果";
    private static final String SCRIPT_RESULT_PASS = "通过";
    private static final String SCRIPT_RESULT_FAIL = "失败";
    private static final String SCRIPT_RESULT_OTHER = "其他";

    private DefaultTableModel tableModel;
    private Vector<Object> scriptTableVector = new Vector<>();

    public ScriptManagerTable() {
        Vector<String> columnNames = new Vector<>();
        columnNames.add(TABLE_COLUMN_ID);
        columnNames.add(TABLE_COLUMN_NAME);
        columnNames.add(TABLE_COLUMN_CASE);
        columnNames.add(TABLE_COLUMN_KEY);
        columnNames.add(TABLE_COLUMN_RESULT);
        // 表结构构造
        refreshScriptTable();
        tableModel = new DefaultTableModel(scriptTableVector, columnNames);
        this.setModel(tableModel);
        TableColumnModel columnModel = this.getColumnModel();
        this.setTableHeader(new EditableHeader(columnModel));

        String[] items = {SCRIPT_RESULT_PASS, SCRIPT_RESULT_FAIL, SCRIPT_RESULT_OTHER};
        JComboBox comboBox = new JComboBox();
        for (String item : items) {
            comboBox.addItem(item);
        }
        comboBox.setSize(50, 30);
        final int index = 4;
        EditableHeaderTableColumn col;
        col = (EditableHeaderTableColumn) this.getColumnModel().getColumn(index);
        col.setHeaderValue(comboBox.getItemAt(0));
        col.setHeaderRenderer(new ComboBoxRenderer(items));
        col.setHeaderEditor(new DefaultCellEditor(comboBox));

        for (int i = 0; i < columnNames.size() - 1; i++) {
            EditableHeaderTableColumn column = (EditableHeaderTableColumn) this.getColumnModel().getColumn(i);
            column.setHeaderEditable(false);
        }

        this.setFillsViewportHeight(true);
        this.setRowHeight(TABLE_ROW_HEIGHT);
        this.getTableHeader().setReorderingAllowed(false);
    }

    private void refreshScriptTable() {
        for (int i = 0; i < 9; i++) {
            Vector<Object> scriptRow = new Vector<Object>();
            scriptRow.add(i);
            scriptRow.add("Name");
            scriptRow.add("case");
            scriptRow.add("key");
            scriptRow.add("pass");
            scriptTableVector.add(scriptRow);
        }
    }

    private static class ComboBoxRenderer extends JComboBox implements TableCellRenderer {

        public ComboBoxRenderer(String[] items) {
            for (String item : items) {
                addItem(item);
            }
        }

        @Override
        public Component getTableCellRendererComponent(
                JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
            setSelectedItem(value);
            return this;
        }
    }

    /**
     * 重写表头
     */
    public static class EditableHeaderUI extends BasicTableHeaderUI {

        protected MouseInputListener createMouseInputListener() {
            return new MouseInputHandler((EditableHeader) header);
        }

        public class MouseInputHandler extends BasicTableHeaderUI.MouseInputHandler {
            private Component dispatchComponent;
            protected EditableHeader header;

            public MouseInputHandler(EditableHeader header) {
                this.header = header;
            }

            private void setDispatchComponent(MouseEvent e) {
                Component editorComponent = header.getEditorComponent();
                Point p = e.getPoint();
                Point p2 = SwingUtilities.convertPoint(header, p, editorComponent);
                dispatchComponent = SwingUtilities.getDeepestComponentAt(editorComponent,
                        p2.x, p2.y);
            }

            private void repostEvent(MouseEvent e) {
                if (dispatchComponent == null) {
                    return;
                }
                MouseEvent e2 = SwingUtilities.convertMouseEvent(header, e, dispatchComponent);
                dispatchComponent.dispatchEvent(e2);
            }

            public void mousePressed(MouseEvent e) {
                if (!SwingUtilities.isLeftMouseButton(e)) {
                    return;
                }
                super.mousePressed(e);
                if (header.getResizingColumn() == null) {
                    Point p = e.getPoint();
                    TableColumnModel columnModel = header.getColumnModel();
                    int index = columnModel.getColumnIndexAtX(p.x);
                    if (index != -1) {
                        if (header.editCellAt(index, e)) {
                            setDispatchComponent(e);
                            repostEvent(e);
                        }
                    }
                }
            }

            public void mouseReleased(MouseEvent e) {
                super.mouseReleased(e);
                if (!SwingUtilities.isLeftMouseButton(e)) {
                    return;
                }
                repostEvent(e);
                dispatchComponent = null;
            }
        }
    }

    /**
     * 定义获取表头行
     */
    public static class EditableHeaderTableColumn extends TableColumn {
        protected TableCellEditor headerEditor;
        protected boolean isHeaderEditable;

        public EditableHeaderTableColumn() {
            setHeaderEditor(createDefaultHeaderEditor());
            isHeaderEditable = true;
        }

        public void setHeaderEditor(TableCellEditor headerEditor) {
            this.headerEditor = headerEditor;
        }

        public TableCellEditor getHeaderEditor() {
            return headerEditor;
        }

        public void setHeaderEditable(boolean isEditable) {
            isHeaderEditable = isEditable;
        }

        public boolean isHeaderEditable() {
            return isHeaderEditable;
        }

        public void copyValues(TableColumn base) {
            modelIndex = base.getModelIndex();
            identifier = base.getIdentifier();
            width = base.getWidth();
            minWidth = base.getMinWidth();
            setPreferredWidth(base.getPreferredWidth());
            maxWidth = base.getMaxWidth();
            headerRenderer = base.getHeaderRenderer();
            headerValue = base.getHeaderValue();
            cellRenderer = base.getCellRenderer();
            cellEditor = base.getCellEditor();
            isResizable = base.getResizable();
        }

        protected TableCellEditor createDefaultHeaderEditor() {
            return new DefaultCellEditor(new JTextField());
        }
    }

    /**
     * 定义可编辑表头
     */
    public static class EditableHeader extends JTableHeader implements CellEditorListener {
        public final int HEADER_ROW = -10;
        transient protected int editingColumn;
        transient protected TableCellEditor cellEditor;
        transient protected Component editorComp;

        public EditableHeader(TableColumnModel columnModel) {
            super(columnModel);
            setReorderingAllowed(false);
            cellEditor = null;
            recreateTableColumn(columnModel);
        }

        public void updateUI() {
            setUI(new EditableHeaderUI());
            resizeAndRepaint();
            invalidate();
        }

        protected void recreateTableColumn(TableColumnModel columnModel) {
            int n = columnModel.getColumnCount();
            EditableHeaderTableColumn[] newCols = new EditableHeaderTableColumn[n];
            TableColumn[] oldCols = new TableColumn[n];
            for (int i = 0; i < n; i++) {
                oldCols[i] = columnModel.getColumn(i);
                newCols[i] = new EditableHeaderTableColumn();
                newCols[i].copyValues(oldCols[i]);
            }
            for (int i = 0; i < n; i++) {
                columnModel.removeColumn(oldCols[i]);
            }
            for (int i = 0; i < n; i++) {
                columnModel.addColumn(newCols[i]);
            }
        }

        public boolean editCellAt(int index, EventObject e) {
            if (cellEditor != null && !cellEditor.stopCellEditing()) {
                return false;
            }
            if (!isCellEditable(index)) {
                return false;
            }
            TableCellEditor editor = getCellEditor(index);
            if (editor != null && editor.isCellEditable(e)) {
                editorComp = prepareEditor(editor, index);
                editorComp.setBounds(getHeaderRect(index));
                add(editorComp);
                editorComp.validate();
                setCellEditor(editor);
                setEditingColumn(index);
                editor.addCellEditorListener(this);
                return true;
            }
            return false;
        }

        public boolean isCellEditable(int index) {
            if (getReorderingAllowed()) {
                return false;
            }
            int columnIndex = columnModel.getColumn(index).getModelIndex();
            EditableHeaderTableColumn col = (EditableHeaderTableColumn) columnModel.getColumn(columnIndex);
            return col.isHeaderEditable();
        }

        public TableCellEditor getCellEditor(int index) {
            int columnIndex = columnModel.getColumn(index).getModelIndex();
            EditableHeaderTableColumn col = (EditableHeaderTableColumn) columnModel.getColumn(columnIndex);
            return col.getHeaderEditor();
        }

        public void setCellEditor(TableCellEditor newEditor) {
            TableCellEditor oldEditor = cellEditor;
            cellEditor = newEditor;

            if (oldEditor != null) {
                oldEditor.removeCellEditorListener(this);
            }
            if (newEditor != null) {
                newEditor.addCellEditorListener(this);
            }
        }

        public Component prepareEditor(TableCellEditor editor, int index) {
            Object value = columnModel.getColumn(index).getHeaderValue();
            JTable table = getTable();
            Component comp = editor.getTableCellEditorComponent(table,
                    value, true, HEADER_ROW, index);
            if (comp instanceof JComponent) {
                ((JComponent) comp).setNextFocusableComponent(this);
            }
            return comp;
        }

        public TableCellEditor getCellEditor() {
            return cellEditor;
        }

        public Component getEditorComponent() {
            return editorComp;
        }

        public void setEditingColumn(int aColumn) {
            editingColumn = aColumn;
        }

        public int getEditingColumn() {
            return editingColumn;
        }

        public void removeEditor() {
            TableCellEditor editor = getCellEditor();
            if (editor != null) {
                editor.removeCellEditorListener(this);

                requestFocus();
                remove(editorComp);

                int index = getEditingColumn();
                Rectangle cellRect = getHeaderRect(index);

                setCellEditor(null);
                setEditingColumn(-1);
                editorComp = null;

                repaint(cellRect);
            }
        }

        public boolean isEditing() {
            return cellEditor != null;
        }

        public void editingStopped(ChangeEvent e) {
            TableCellEditor editor = getCellEditor();
            if (editor != null) {
                Object value = editor.getCellEditorValue();
                int index = getEditingColumn();
                columnModel.getColumn(index).setHeaderValue(value);
                removeEditor();
            }
        }

        public void editingCanceled(ChangeEvent e) {
            removeEditor();
        }
    }
}
